using System;
using System.Collections.Generic;
using System.IO;
using FireStarter.Base;
using FireStarter.CodeGeneration;
using FireStarterModeller.BO;
using Habanero.Util;
using NUnit.Framework;

namespace FireStarter.Test.CodeGeneration
{
    [TestFixture]
    public class TestSolutionGenerator : TestGeneratorBase
    {

        private SolutionGenerator CreateSolutionGenerator()
        {
            return new SolutionGenerator();
        }

        private SolutionGenerator CreateSolutionGeneratorReadyToGenerate()
        {
            SolutionGenerator solutionGenerator = CreateSolutionGenerator();
            solutionGenerator.SolutionName = GetRandomString();
            solutionGenerator.SolutionDirectory = GetRootedPath(GetRandomString());
            return solutionGenerator;
        }

        [Test]
        public void Test_Constructor()
        {
            //---------------Set up test pack-------------------
            
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            ISolutionGenerator solutionGenerator = new SolutionGenerator();
            //---------------Test Result -----------------------
            Assert.IsNotNull(solutionGenerator.ProjectGenerators);
            Assert.AreEqual(0, solutionGenerator.ProjectGenerators.Count);
            Assert.IsNotNull(solutionGenerator.ModelClasses);
            Assert.AreEqual(0, solutionGenerator.ModelClasses.Count);
        }

        [Test]
        public void TestSolutionName()
        {
            //---------------Set up test pack-------------------
            string SolutionName = GetRandomString();
            SolutionGenerator solutionGenerator = CreateSolutionGenerator();
            //---------------Assert Precondition----------------
            Assert.IsNull(solutionGenerator.SolutionName);
            //---------------Execute Test ----------------------
            solutionGenerator.SolutionName = SolutionName;
            //---------------Test Result -----------------------
            Assert.AreEqual(SolutionName, solutionGenerator.SolutionName);
        }

        [Test]
        public void TestSolutionTypeName()
        {
            //---------------Set up test pack-------------------
            string solutionTypeName = GetRandomString();
            SolutionGenerator solutionGenerator = CreateSolutionGenerator();
            //---------------Assert Precondition----------------
            Assert.IsNull(solutionGenerator.SolutionTypeName);
            //---------------Execute Test ----------------------
            solutionGenerator.SolutionTypeName = solutionTypeName;
            //---------------Test Result -----------------------
            Assert.AreEqual(solutionTypeName, solutionGenerator.SolutionTypeName);
        }

        [Test]
        public void TestModelClasses()
        {
            //---------------Set up test pack-------------------
            List<IModelClass> modelClasses = new List<IModelClass>();
            modelClasses.Add(new DMClass());
            SolutionGenerator solutionGenerator = CreateSolutionGenerator();
            //---------------Assert Precondition----------------
            Assert.IsNotNull(solutionGenerator.ModelClasses);
            Assert.AreEqual(0, solutionGenerator.ModelClasses.Count);
            //---------------Execute Test ----------------------
            solutionGenerator.ModelClasses = modelClasses;
            //---------------Test Result -----------------------
            Assert.AreEqual(modelClasses, solutionGenerator.ModelClasses);
        }

        [Test]
        public void TestGenerate_Fails_SolutionNameNotSet()
        {
            //---------------Set up test pack-------------------
            SolutionGenerator solutionGenerator = CreateSolutionGeneratorReadyToGenerate();
            solutionGenerator.SolutionName = null;
            //---------------Assert Precondition----------------
            Assert.IsNull(solutionGenerator.SolutionName);
            //---------------Execute Test ----------------------
            Exception exception = null;
            try
            {
                solutionGenerator.Generate(CodeTemplateEnum.CSharpVisualStudio2005);
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            //---------------Test Result -----------------------
            Assert.IsNotNull(exception, "Exception Expected");
            Assert.IsInstanceOf(typeof(PropertyMissingException), exception);
            PropertyMissingException propertyMissingException = (PropertyMissingException)exception;
            Assert.AreEqual("SolutionName", propertyMissingException.PropertyName);
        }

        [Test]
        public void TestSolutionPath()
        {
            //---------------Set up test pack-------------------
            string SolutionPath = GetRandomString();
            SolutionGenerator solutionGenerator = CreateSolutionGenerator();
            //---------------Assert Precondition----------------
            Assert.IsNull(solutionGenerator.SolutionDirectory);
            //---------------Execute Test ----------------------
            solutionGenerator.SolutionDirectory = SolutionPath;
            //---------------Test Result -----------------------
            Assert.AreEqual(SolutionPath, solutionGenerator.SolutionDirectory);
        }

        [Test]
        public void Test_ProjectGenerators_CanAccessAndAdd()
        {
            //---------------Set up test pack-------------------
            SolutionGenerator solutionGenerator = new SolutionGenerator();
            //---------------Assert Precondition----------------
            Assert.AreEqual(0, solutionGenerator.ProjectGenerators.Count);
            //---------------Execute Test ----------------------
            BoProjectGenerator projectGenerator = new BoProjectGenerator();
            solutionGenerator.ProjectGenerators.Add(projectGenerator);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, solutionGenerator.ProjectGenerators.Count);
            Assert.AreSame(projectGenerator, solutionGenerator.ProjectGenerators[0]);
        }

        [Test]
        public void TestGenerate_Fails_SolutionPathNotSet()
        {
            //---------------Set up test pack-------------------
            SolutionGenerator solutionGenerator = CreateSolutionGeneratorReadyToGenerate();
            solutionGenerator.SolutionDirectory = null;
            //---------------Assert Precondition----------------
            Assert.IsNull(solutionGenerator.SolutionDirectory);
            //---------------Execute Test ----------------------
            Exception exception = null;
            try
            {
                solutionGenerator.Generate(CodeTemplateEnum.CSharpVisualStudio2005);
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            //---------------Test Result -----------------------
            Assert.IsNotNull(exception, "Exception Expected");
            Assert.IsInstanceOf(typeof(PropertyMissingException), exception);
            PropertyMissingException propertyMissingException = (PropertyMissingException)exception;
            Assert.AreEqual("SolutionDirectory", propertyMissingException.PropertyName);
        }

        [Test]
        public void TestGenerate_OneProject()
        {
            //---------------Set up test pack-------------------
            SolutionGenerator solutionGenerator = CreateSolutionGeneratorReadyToGenerate();
            string projectName = GetRandomString();
            string projectFileName = CreateProjectGenerator(projectName, solutionGenerator);

            ProjectFileManager projectFileManager = new ProjectFileManager(projectFileName, OutputType.Library, CodeTemplateEnum.CSharpVisualStudio2005);
            projectFileManager.SaveProjectFile();
            //-------------Assert Preconditions -------------

            //---------------Execute Test ----------------------
            solutionGenerator.Generate(CodeTemplateEnum.CSharpVisualStudio2005);
            //---------------Test Result -----------------------
            Assert.IsTrue(File.Exists(solutionGenerator.SolutionFileName));
            SolutionFileManager solutionFileManager = new SolutionFileManager(solutionGenerator.SolutionFileName, CodeTemplateEnum.CSharpVisualStudio2005);
            Assert.IsTrue(solutionFileManager.HasProjectFile(projectFileName));
        }

        [Test]
        public void TestGenerate_TwoProjects()
        {
            //---------------Set up test pack-------------------
            SolutionGenerator solutionGenerator = CreateSolutionGeneratorReadyToGenerate();
            string projectName1 = GetRandomString();
            string projectName2 = GetRandomString();
            string projectFileName1 = CreateProjectGenerator(projectName1, solutionGenerator);
            string projectFileName2 = CreateProjectGenerator(projectName2, solutionGenerator);

            ProjectFileManager projectFileManager = new ProjectFileManager(projectFileName1, OutputType.Library, CodeTemplateEnum.CSharpVisualStudio2005);
            projectFileManager.SaveProjectFile();
            projectFileManager = new ProjectFileManager(projectFileName2, OutputType.Library, CodeTemplateEnum.CSharpVisualStudio2005);
            projectFileManager.SaveProjectFile();
            //-------------Assert Preconditions -------------

            //---------------Execute Test ----------------------
            solutionGenerator.Generate(CodeTemplateEnum.CSharpVisualStudio2005);
            //---------------Test Result -----------------------
            Assert.IsTrue(File.Exists(solutionGenerator.SolutionFileName));
            SolutionFileManager solutionFileManager = new SolutionFileManager(solutionGenerator.SolutionFileName, CodeTemplateEnum.CSharpVisualStudio2005);
            Assert.IsTrue(solutionFileManager.HasProjectFile(projectFileName1));
            Assert.IsTrue(solutionFileManager.HasProjectFile(projectFileName2));
        }

        [Test, Ignore("")] //TODO Eric 21 Aug 2009: check this out, does it work in real
        public void TestGenerate_SortsProjects()
        {
            //---------------Set up test pack-------------------
            SolutionGenerator solutionGenerator = CreateSolutionGeneratorReadyToGenerate();
            const string projectName1 = "testproj2";
            const string projectName2 = "testproj1";
            string projectFileName1 = CreateProjectGenerator(projectName1, solutionGenerator);
            string projectFileName2 = CreateProjectGenerator(projectName2, solutionGenerator);

            ProjectFileManager projectFileManager = new ProjectFileManager(projectFileName1, OutputType.Library, CodeTemplateEnum.CSharpVisualStudio2005);
            projectFileManager.SaveProjectFile();
            projectFileManager = new ProjectFileManager(projectFileName2, OutputType.Library, CodeTemplateEnum.CSharpVisualStudio2005);
            projectFileManager.SaveProjectFile();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            solutionGenerator.Generate(CodeTemplateEnum.CSharpVisualStudio2005);
            //---------------Test Result -----------------------
            Assert.IsTrue(File.Exists(solutionGenerator.SolutionFileName));
            string fileContents = File.ReadAllText(solutionGenerator.SolutionFileName);
            AssertTextComesFirst("testproj1.csproj", "testproj2.csproj", fileContents);
        }

        private static void AssertTextComesFirst(string firstText, string lastText, string fileContents)
        {
            string leftSection = StringUtilities.GetLeftSection(fileContents, lastText);
            Assert.IsTrue(leftSection.Contains(firstText), String.Format("Expected '{0}' before '{1}'", firstText, lastText));
        }

        private static string CreateProjectGenerator(string projectName, ISolutionGenerator solutionGenerator)
        {
            ProjectGeneratorStub projectGenerator = new ProjectGeneratorStub();
            projectGenerator.ProjectName = projectName;
            projectGenerator.ProjectPath = Environment.CurrentDirectory;
            solutionGenerator.ProjectGenerators.Add(projectGenerator);
            return GetRootedPath(projectGenerator.ProjectFileName);
        }
    }
}
